# coding: utf-8
from mnist import load_mnist
import pickle
import numpy as np
###写在前面的话，此神经网络的实现主要侧重于其中的推理阶段，所以权重和偏置参数我们直接使用现成的
###介绍一下这个神经网络的大概组成：输入层（784个神经元）、输出层（10个神经元，分别代表分类的十种结果，即图片中是数字0还是数字9）
###2个隐藏层，第一个隐藏层50个神经元、第二个隐藏层100个神经元

#一般层的激活函数
def sigmoid(x):
    return 1/(1+np.exp(-x))

#输出层的softmax激活函数
def softmax(x):
    c = np.max(x)
    exp_x = np.exp(x - c)
    return exp_x/np.sum(exp_x)


#获取测试数据
def get_data():
    (x_train,t_train),(x_test,t_test) = \
        load_mnist(normalize=True,flatten=True,one_hot_label=False)
    return x_test,t_test

#初始化权重（利用别人已经学习得的数据，来进行初始化）
#sample_weight.pkl文件中已字典形式保存好了我们所需要用的的权重和偏置
def init_network():
    with open("sample_weight.pkl",'rb') as f:
        network = pickle.load(f)
    return network

#使用神经网络进行分类推理
def predict(network,x):
    W1,W2,W3 = network['W1'],network['W2'],network['W3']
    b1,b2,b3 = network['b1'],network['b2'],network['b3']
    a1 = np.dot(x,W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1,W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2,W3) + b3
    y = softmax(a3)
    return y

#单张单张图片处理模式
def single_processing():
    x,t = get_data()
    network = init_network()
    accuracy_cnt = 0
    for i in range(len(x)):
        y = predict(network,x[i])
        p = np.argmax(y)  #获取概率最高的索引（其正好就对应我们需要的答案）
        if p == t[i]:
            accuracy_cnt += 1  #统计预测正确的数目
    print("Accuracy:" + str(float(accuracy_cnt)/len(x)))  #输出识别精度，即在多大程度上能正确判断，应为：0.9352

#多张图片同时处理模式（这里是100张100张的处理，也刚好因为数据量刚好为100的整数倍，所以不会出现索引溢出的错误，也或许python的for循环中针对这种情况是有处理对策的）
def batch_processing():
    x,t = get_data()
    network = init_network()
    accuracy_cnt = 0
    batch_size = 100
    for i in range(0,len(x),batch_size):
        y = predict(network,x[i:i+batch_size])
        p = np.argmax(y,1)  #获取概率最高的索引（其正好就对应我们需要的答案),1这个参数代表以第一维的方向输出索引，这里即指以行的方向
        accuracy_cnt += np.sum(p == t[i:i+batch_size])   #统计预测正确的数目
    print("Accuracy:" + str(float(accuracy_cnt)/len(x)))  #输出识别精度，即在多大程度上能正确判断，应为：0.9352

if __name__ == '__main__':
    single_processing()  #单处理模式的结果
    batch_processing()  #批处理模式的结果



